package com.ss.project.xia17user.config.security.form;

import com.ss.project.xia17user.config.sys.SysConfigManager;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderNotFoundException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Form 认证
 * @author xia17
 * @date 2020/6/21
 */
public class FormAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private final SysConfigManager sysConfigManager;
    private final FormAuthenticationProvider formAuthenticationProvider;

    /**
     * 只拦截 Post方法 的 /login 请求
     * @param authenticationManager /
     * @param sysConfigManager /
     */
    public FormAuthenticationFilter(final SysConfigManager sysConfigManager , final UserDetailsService userDetailsService , final AuthenticationManager authenticationManager) {
        super(new AntPathRequestMatcher("/login", HttpMethod.POST.name()));
        this.setAuthenticationFailureHandler(new FormAuthenticationFailureHandler());
        this.setAuthenticationSuccessHandler(new FormAuthenticationSuccessHandler());
        this.setAuthenticationManager(authenticationManager);
        this.sysConfigManager = sysConfigManager;
        this.formAuthenticationProvider = new FormAuthenticationProvider(userDetailsService);
    }

    /**
     * 尝试认证
     * @param req /
     * @param resp /
     * @return /
     * @throws AuthenticationException /
     * @throws IOException /
     * @throws ServletException /
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse resp) throws AuthenticationException, IOException, ServletException {
        // 从请求中获取参数
        Assert.hasText(req.getParameter(LoginAttributesNames.LOGIN_METHOD),"参数异常 ，loginMethod is empty !");
        // 是否支持登录方式
        LoginMethod loginMethod = sysConfigManager.supportLoginMethod(req.getParameter(LoginAttributesNames.LOGIN_METHOD));
        if (loginMethod == null){
            throw new ProviderNotFoundException("暂不支持该登录方式");
        }
        // 用户名
        String username = req.getParameter(LoginAttributesNames.USERNAME);
        Assert.hasText(username,"参数异常 ，username is empty !");
        // 凭证
        String credentials = this.obtainCredentials(loginMethod, req);
        // 认证
        Authentication authenticate = formAuthenticationProvider.authenticate(new FormAuthentication(username, credentials, loginMethod));
        // 写入登录信息
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        return authenticate;
    }

    /**
     * 从请求中获取凭证
     * @param loginMethod 登录方式
     * @param req 请求信息
     * @return  凭证
     */
    private String obtainCredentials(LoginMethod loginMethod , HttpServletRequest req){
        String credentials = "" ;
        // 登录方式不同凭证字段不同
        switch (loginMethod){
            case PASSWORD:{
                credentials = req.getParameter(LoginAttributesNames.PASSWORD);
                Assert.hasText(credentials,"参数异常 ，password is empty !");
                break;
            }
            case EMAIL_CODE:{
                // 邮箱登录暂无
            }
        }
        return credentials;
    }








}
